home *** CD-ROM | disk | FTP | other *** search
- /* +-------------------------------------------------------------------+ */
- /* | Copyright 1993, David Koblas (koblas@netcom.com) | */
- /* | | */
- /* | Permission to use, copy, modify, and to distribute this software | */
- /* | and its documentation for any purpose is hereby granted without | */
- /* | fee, provided that the above copyright notice appear in all | */
- /* | copies and that both that copyright notice and this permission | */
- /* | notice appear in supporting documentation. There is no | */
- /* | representations about the suitability of this software for | */
- /* | any purpose. this software is provided "as is" without express | */
- /* | or implied warranty. | */
- /* | | */
- /* +-------------------------------------------------------------------+ */
-
- #include <X11/Intrinsic.h>
- #include <X11/cursorfont.h>
- #include "image.h"
-
- #define GRAB_FAST
-
- /*
- ** Convienence function. For doing server pointer grabs
- **
- */
- #define GRAB_INTERVAL 30
-
- typedef struct {
- XtAppContext app;
- Display *dpy;
- GC gc;
- Window root;
- Boolean drawn;
- int x, y, ox, oy, width, height;
- XtIntervalId id;
- } GrabInfo;
-
- static void grabHilite(XtPointer infoArg, XtIntervalId *id)
- {
- GrabInfo *info = (GrabInfo*)infoArg;
-
- if (info->drawn) {
- if (info->ox == info->x && info->oy == info->y)
- goto end;
-
- XDrawRectangle(info->dpy, info->root, info->gc,
- info->ox - info->width / 2,
- info->oy - info->height / 2,
- info->width, info->height);
- }
- info->drawn = True;
-
- XDrawRectangle(info->dpy, info->root, info->gc,
- info->x - info->width / 2,
- info->y - info->height / 2,
- info->width, info->height);
- info->ox = info->x;
- info->oy = info->y;
-
- end:
- info->id = XtAppAddTimeOut(info->app, GRAB_INTERVAL,
- grabHilite, (XtPointer)info);
- }
-
- static void xyToWindowCmap(Display *dpy, int x, int y, Window base,
- int *nx, int *ny, Window *window, Colormap *cmap)
- {
- Window twin;
- Colormap tmap;
- Window child, sub;
- XWindowAttributes attr;
-
- twin = base;
- tmap = None;
-
- sub = base;
- *nx = x;
- *ny = y;
-
- while (sub != None) {
- x = *nx;
- y = *ny;
- child = sub;
- XTranslateCoordinates(dpy, base, child, x, y, nx, ny, &sub);
- base = child;
-
- XGetWindowAttributes(dpy, child, &attr);
- if (attr.class == InputOutput && attr.colormap != None) {
- tmap = attr.colormap;
- twin = child;
- }
- }
-
- if (tmap == None)
- *cmap = DefaultColormap(dpy, DefaultScreen(dpy));
- else
- *cmap = tmap;
- *window = twin;
- }
-
- static void doGrab(Widget w, int width, int height, int *x, int *y)
- {
- Display *dpy = XtDisplay(w);
- XtAppContext app = XtWidgetToApplicationContext(w);
- Window root = DefaultRootWindow(dpy);
- XEvent event;
- Cursor cursor = XCreateFontCursor(dpy, XC_crosshair);
- int count = 0;
- GrabInfo *info = NULL;
-
- if (width != 0 && height != 0) {
- XGCValues gcv;
- info = XtNew(GrabInfo);
- gcv.function = GXxor;
- gcv.foreground = 1;
- gcv.subwindow_mode = IncludeInferiors;
- info->root = root;
- info->app = app;
- info->x = 0;
- info->y = 0;
- info->drawn = False;
- info->dpy = dpy;
- info->gc = XCreateGC(dpy, root, GCSubwindowMode|GCForeground|GCFunction, &gcv);
- info->width = width;
- info->height = height;
- info->id = XtAppAddTimeOut(app, GRAB_INTERVAL,
- grabHilite, (XtPointer)info);
- }
-
- if (XGrabPointer(dpy, root, False,
- info == NULL ? ButtonPressMask|ButtonReleaseMask
- : ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
- GrabModeSync, GrabModeAsync,
- root, cursor, CurrentTime)) {
- return;
- }
-
- do {
- XAllowEvents(dpy, SyncPointer, CurrentTime);
- XtAppNextEvent(app, &event);
- if (event.type == ButtonPress)
- count++;
- else if (event.type == ButtonRelease) {
- if (count == 1)
- break;
- else
- count--;
- } else if (event.type == MotionNotify) {
- info->x = event.xmotion.x;
- info->y = event.xmotion.y;
- } else
- XtDispatchEvent(&event);
- } while (True);
-
- XUngrabPointer(dpy, CurrentTime);
-
- if (info != NULL) {
- if (info->drawn)
- XDrawRectangle(info->dpy, info->root, info->gc,
- info->ox - info->width / 2,
- info->oy - info->height / 2,
- info->width, info->height);
- XtRemoveTimeOut(info->id);
- XFreeGC(XtDisplay(w), info->gc);
- XtFree((XtPointer)info);
- }
-
- *x = event.xbutton.x;
- *y = event.xbutton.y;
- }
-
- void *DoGrabImage(Widget w, int width, int height)
- {
- Screen *screen = XtScreen(w);
- Display *dpy = XtDisplay(w);
- Window root = RootWindowOfScreen(screen);
- Colormap dmap = DefaultColormapOfScreen(screen);
- int x, y, xi, yi, count, nx, ny, i, tx, ty;
- int fx, fy;
- Colormap cmap, lastCmap;
- Window window, lastWindow;
- unsigned char *ip;
- Image *image;
- XColor *xcol;
- XImage *xim;
-
- doGrab(w, width, height, &x, &y);
-
- x -= width / 2;
- y -= height / 2;
-
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (y < 0) {
- height += y;
- y = 0;
- }
- if (x + width > WidthOfScreen(screen))
- width = WidthOfScreen(screen) - x;
- if (y + height > HeightOfScreen(screen))
- height = HeightOfScreen(screen) - x;
-
- if (width == 0 || height == 0)
- return NULL;
-
- image = ImageNew(width, height);
- ip = image->data;
-
- xcol = (XColor *)XtCalloc(width, sizeof(XColor));
- #ifdef GRAB_FAST
- /*
- ** Fast grabs, just use the colormap at the 0,0 position
- ** gotcha is that the XImage is from the root window
- ** thus, with it's depth.
- */
-
- xyToWindowCmap(dpy, x, y, root, &nx, &ny, &window, &cmap);
- xyToWindowCmap(dpy, x + width, y + height, root, &tx, &ty, &lastWindow, &lastCmap);
-
- /*
- ** XXX Improvment:
- ** instead of window == lastWindow
- ** we could check for common parent, and use that.
- */
- if (window == lastWindow)
- xim = XGetImage(dpy, window, nx, ny, width, height, AllPlanes, ZPixmap);
- else
- xim = XGetImage(dpy, root, x, y, width, height, AllPlanes, ZPixmap);
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- xcol[x].pixel = XGetPixel(xim, x, y);
- xcol[x].flags = DoRed|DoGreen|DoBlue;
- }
- XQueryColors(XtDisplay(w), cmap, xcol, width);
- for (x = 0; x < width; x++) {
- *ip++ = (xcol[x].red >> 8) & 0xff;
- *ip++ = (xcol[x].green >> 8) & 0xff;
- *ip++ = (xcol[x].blue >> 8) & 0xff;
- }
- }
- #else
- /*
- ** Slow grabs, get the correct color and colormap though a lot of
- ** server calls.
- */
- StateSetBusyWatch(True);
-
- for (yi = 0; yi < height; yi++) {
- count = 0;
- lastCmap = None;
- lastWindow = None;
- for (xi = 0; xi < width; xi++, count++) {
- xyToWindowCmap(dpy, xi + x, yi + y, root, &nx, &ny, &window, &cmap);
- if ((window != lastWindow || cmap != lastCmap) && count != 0) {
- if (cmap == lastCmap && lastWindow == root)
- continue;
-
- xim = XGetImage(dpy, lastWindow, fx, fy, count, 1,
- AllPlanes, ZPixmap);
-
- for (i = 0; i < count; i++) {
- xcol[i].pixel = XGetPixel(xim, i, 0);
- xcol[i].flags = DoRed|DoGreen|DoBlue;
- }
- XQueryColors(XtDisplay(w), lastCmap, xcol, count);
-
- for (i = 0; i < count; i++) {
- *ip++ = (xcol[i].red >> 8) & 0xff;
- *ip++ = (xcol[i].green >> 8) & 0xff;
- *ip++ = (xcol[i].blue >> 8) & 0xff;
- }
-
- XDestroyImage(xim);
-
- count = 0;
- }
-
- if (count == 0) {
- fx = nx;
- fy = ny;
- if (cmap == dmap) {
- fx = x + xi;
- fy = y + yi;
- lastWindow = root;
- } else {
- lastWindow = window;
- }
- lastCmap = cmap;
- }
- }
- if (count != 0) {
- xim = XGetImage(dpy, lastWindow, fx, fy, count, 1,
- AllPlanes, ZPixmap);
-
- for (i = 0; i < count; i++) {
- xcol[i].pixel = XGetPixel(xim, i, 0);
- xcol[i].flags = DoRed|DoGreen|DoBlue;
- }
- XQueryColors(XtDisplay(w), lastCmap, xcol, count);
-
- for (i = 0; i < count; i++) {
- *ip++ = (xcol[i].red >> 8) & 0xff;
- *ip++ = (xcol[i].green >> 8) & 0xff;
- *ip++ = (xcol[i].blue >> 8) & 0xff;
- }
-
- XDestroyImage(xim);
- }
- }
-
- StateSetBusyWatch(False);
- #endif
-
- XtFree((XtPointer)xcol);
- XDestroyImage(xim);
-
- return (void*)image;
- }
-
- void DoGrabPixel(Widget w, Pixel *p, Colormap *cmap)
- {
- int x, y, nx, ny;
- XImage *xim;
- Colormap amap;
- Window root = RootWindowOfScreen(XtScreen(w));
- Window window;
- Display *dpy = XtDisplay(w);
-
- doGrab(w, 0, 0, &x, &y);
-
- if (cmap == NULL)
- cmap = &amap;
-
- xyToWindowCmap(dpy, x, y, root, &nx, &ny, &window, cmap);
-
- xim = XGetImage(dpy, window, nx, ny, 1, 1, AllPlanes, ZPixmap);
-
- if (p != NULL)
- *p = XGetPixel(xim, 0, 0);
-
- XDestroyImage(xim);
- }
-
- XColor *DoGrabColor(Widget w)
- {
- static XColor xcol;
- Colormap cmap;
- Pixel p;
-
- DoGrabPixel(w, &p, &cmap);
-
- xcol.pixel = p;
- xcol.flags = DoRed|DoGreen|DoBlue;
- XQueryColor(XtDisplay(w), cmap, &xcol);
-
- return &xcol;
- }
-